#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : Fri May 17 2019
# @Author  : xujunfu (xjf891121@gmail.com})
# @Link    : http://junfuxu.github.io/
import json
import logging
import time
import uuid
from datetime import datetime, timedelta

import pymysql
import requests
import urllib3

from const import VEHICLE_INFOS, YB2ZSH_MAP
from sql import (SQL_EVENT_WARNING_INFO, SQL_LOCATION,
                 SQL_QUERY_POSITION, SQL_WARNING_INFO)

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
logging.basicConfig(level=logging.INFO)

MYSQL_CONFIG = {
    'host': 'mysql-v0.i.123yb.cn',
    'port': 3306,
    'user': 'ybad',
    'password': 'qwer!@#$1234',
    'db': 'SICP',
    'charset': 'utf8mb4',
    'cursorclass': pymysql.cursors.DictCursor
}


class ApiZhongShiHua:
    VENDER_CODE = 'YBAD'
    FORMAT_DT = '%Y-%m-%d %H:%M:%S'
    URL_BASE = 'https://219.143.119.224/RD/'
    FILE_STATUS = 'start_ids.json'
    COORDINATE = 'GCJ02'
    LIMIT = 5000

    def __init__(self, *args, **kwargs):
        self.tmpl_headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json, text/plain, */*',
            'Date': 'Fri, 17 May 2019 05:22:59 GMT',
            'apiName': 'youbanganda',
            'apiToken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.jLHatDKHnNd8V1HGxbIEdlBKU9PjN_0ovJfQCvw9Z9A',
        }
        self.logger = logging.getLogger(self.__class__.__name__)
        self.vehicle_infos = VEHICLE_INFOS
        with open(self.FILE_STATUS) as f:
            self.start_ids = json.load(f)

    def start(self):
        self.logger.info(f'=== Started at {datetime.now()}')
        self.send_vehicle_event()
        self.send_vehicle_position()
        self.send_warning_info()

    def update_start_ids(self):
        if self._is_a_new_day():
            self.start_ids['vehiclePosition'] = 0

        with open(self.FILE_STATUS, 'w') as f:
            json.dump(self.start_ids, f)

    @property
    def headers(self):
        '''make header
        'Date': 'Fri, 17 May 2019 05:22:59 GMT',
        '''
        dt = datetime.utcnow()
        self.tmpl_headers['Date'] = dt.strftime('%a, %d %b %Y %H:%M:%S GMT')
        return self.tmpl_headers

    @property
    def table_dt(self):
        dt = datetime.utcnow() + timedelta(hours=8)
        return dt.strftime('%Y%m%d')

    def send(self, method_name, item_list):
        if item_list:
            url = f'{self.URL_BASE}{method_name}NFj'
            uid = str(uuid.uuid1())
            data = {
                'msgId': str(uid),
                method_name: item_list,
            }
            assert isinstance(item_list, list)
            self.logger.info(f'>>> DO POST {method_name}, data_len={len(item_list)}')
            resp = requests.post(url=url, data={method_name: json.dumps(data, ensure_ascii=False)}, headers=self.headers, verify=False)
            self.logger.info(url)
            self.logger.info(resp.content)
            if resp.json()['responseCode'] != 200:
                raise ValueError(f'<<< ERROR RESP:{resp.json()}')

        self.logger.info(f'{method_name} {self.start_ids}')
        self.logger.info(item_list[0])
        self.logger.info(item_list[-1])
        self.update_start_ids()

    def send_vehicle_event(self):
        '''3.4 车辆事件同步
        'vehicleEvent': [
            {
            "dispatchNo ": "5178933",
            "eid ": "SHYK_5178933",
            "vno": "京Q88888",
            "color": "蓝",
            "type": "0x10",
            "start_time": "2015-01-01 12:00:00",
            "end_time ": "2015-01-01 13:00:00",
            "coordinate ": " WGS84",
            "start_lng": "114.23074871003",
            "start_lat": "29.579084787993",
            "end_lng": "114.23075628327",
            "end_lat": "29.579081090996",
            "speed": "120",
            "eventGrade": "1",
            "create_time": "2015-01-01 12:00:00",
            "update_time": "2015-01-02 12:00:00",
            "source ": "SHYK",
            "reserve1": "",
            "reserve2": ""
        },
        {
            'eid': 576460,
            'end_time': datetime.datetime(2019, 5, 5, 5, 38, 12),
            'speed': '1.0',
            'start_lat': '30.937273',
            'start_lng': '119.2061',
            'start_time': datetime.datetime(2019, 4, 9, 10, 42, 46),
            'type': '2',
            'vehicle_id': '90000000103',
        },
        {},
        ]
        '''
        method_name = 'vehicleEvent'
        # get status

        warning_info_sql = SQL_EVENT_WARNING_INFO.format(
            vehicle_id_list=','.join(self.vehicle_infos.keys()),
            last_start_id=self.start_ids[method_name],
            limit=self.LIMIT,
        )
        num, warning_infos = self.read_data(warning_info_sql)
        event_list = []
        for row in warning_infos:
            location_sql = SQL_LOCATION.format(
                vehicle_id=row['vehicle_id'],
                start_time=row['start_time'],
                table_dt=self.table_dt,
            )
            n, location_infos = self.read_data(location_sql)
            if location_infos:
                location_infos[0].pop('id')
                row.update(location_infos[0])
            else:
                row.update({'speed': 0, 'end_time': row['start_time']})
            event = self._make_vehicle_event(row)
            if event:
                event_list.append(event)
            self.start_ids[method_name] = row['id']
        if event_list:
            self.send(method_name, event_list)
        return num

    def _make_vehicle_event(self, row):
        event_type = YB2ZSH_MAP.get(row['warning_id'], None)
        if not event_type:  # 没找到映射事件
            return None
        try:
            event = {
                'dispatchNo': "",
                'eid': f'{self.VENDER_CODE}_{row["id"]}',
                'vno': self.vehicle_infos[row['vehicle_id']],
                'color': '黄',
                'type': event_type,
                "driver": "",
                'start_time': row['start_time'].strftime(self.FORMAT_DT),
                'end_time': row['end_time'].strftime(self.FORMAT_DT),
                'coordinate': 'WGS84',
                'start_lng': row['start_lng'] or row['gps_lon'],
                'start_lat': row['start_lat'] or row['gps_lat'],
                'end_lng': '',  # 非必填
                'end_lat': '',  # 非必填
                'speed': str(int(float(row['speed']))),
                'eventGrade': '1',
                'create_time': row['create_time'].strftime(self.FORMAT_DT),
                'update_time': '',  # 非必填
                'source ': self.VENDER_CODE,
                'reserve1': '',
                'reserve2': ''
            }
        except Exception as e:
            print(e)
        return event

    def _is_a_new_day(self):
        dt = datetime.utcnow() + timedelta(hours=8)
        dt_st = datetime(
            year=dt.year,
            month=dt.month,
            day=dt.day,
            hour=0,
            minute=2,
        )
        dt_ed = dt_st + timedelta(minutes=8)
        if dt_st < dt < dt_ed:
            return True
        return False

    def send_vehicle_position(self):
        '''3.5 车辆当前位置信息
        'vehiclePosition': [
            {
                "dispatchNo ": "",
                "vno": "京Q88888",
                "color": "蓝",
                "type": "0",
                "coordinate":" GCJ02",
                "lng": "114.2307487172",
                "lat": "37.597384787432",
                # "address": "",
                # "speed": "120",
                # "course": "180",
                "time": "1556162489000",
                "source":"SHYK",
                "reserve1": "",
                "reserve2": ""
            },
            ...
        ]
        '''
        method_name = 'vehiclePosition'
        # query
        position_list = []
        query = SQL_QUERY_POSITION.format(
            vehicle_id_list=','.join(self.vehicle_infos.keys()),
            table_dt=self.table_dt,
            last_start_id=self.start_ids[method_name],
            limit=self.LIMIT,
        )
        _, results = self.read_data(query)
        num = len(results)
        for row in results:
            position_list.append(self._make_vehicle_position(row))
            self.start_ids[method_name] = row['id']
        if position_list:
            self.send(method_name, position_list)
        return num

    def _make_vehicle_position(self, row):
        return {
            'dispatchNo ': "",
            'vno': self.vehicle_infos[row['vehicle_id']],
            'color': '黄',
            'type': row['type'],
            'coordinate': self.COORDINATE,
            'lng': row['lng'],
            'lat': row['lat'],
            'address': '',
            'speed': str(int(float(row['speed']))),
            'course': row['course'],
            'time': str(row['time']),
            'source': self.VENDER_CODE,
            'reserve1': '',
            'reserve2': '',
        }

    def send_warning_info(self):
        # 发送视频/图片报警信息
        method_name = 'WarningInfo'
        # get status
        YB_MEDIA_HOST = 'https://oss-zsh.123yb.cn/warn/'
        sql = SQL_WARNING_INFO.format(
            vehicle_id_list=','.join(self.vehicle_infos.keys()),
            last_start_id=self.start_ids[method_name],
            limit=self.LIMIT,
        )
        num, results = self.read_data(sql)
        picture_list = []
        video_list = []
        for row in results:
            event_type = YB2ZSH_MAP.get(row['warning_id'], None)
            if not event_type:  # 没找到映射事件
                continue
            if row['photo_url']:
                data = {
                    'Pictures': [
                        {
                            "channel": row['warning_type'],
                            "desc": '',
                            "url": YB_MEDIA_HOST + row['photo_url']
                        }
                    ]
                }
            else:
                data = {
                    'Videos': [
                        {
                            "channel": row['warning_type'],
                            "desc": '',
                            "url": YB_MEDIA_HOST + row['video_url']
                        }
                    ]
                }

            item = {
                'eid': f'{self.VENDER_CODE}_{row["id"]}',
                'vno': self.vehicle_infos[row['vehicle_id']],
                "color": "黄",
                "type": event_type,
                "driver": "",
                "create_time":  row['warning_time'].strftime('%Y-%m-%d %H:%M:%S'),
                "data": data
            }
            self.start_ids[method_name] = row['id']
            if row['photo_url']:
                picture_list.append(item)
            else:
                video_list.append(item)
        if video_list:
            self.logger.info(f'video_list = {video_list}')
            self.send('vehicleEventVideo',  video_list)
        if picture_list:
            self.logger.info(f'picture_list = {picture_list}')
            self.send('vehicleEventPicture',  picture_list)
        return num

    def read_data(self, query):
        '''TODO: USE ONLY ONE CONNECTION
        '''
        if 'id, vehicle_id, speed, location_time as end_time, gps_lon, gps_lat' not in query:
            self.logger.info(query)
        conn = pymysql.connect(**MYSQL_CONFIG)
        with conn.cursor() as cursor:
            try:
                number_of_rows = cursor.execute(query)
                return number_of_rows, cursor.fetchall()
            finally:
                conn.commit()
                cursor.close()
                conn.close()


if __name__ == "__main__":
    api_zsh = ApiZhongShiHua()
    api_zsh.start()
